home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / Documentation / develop articles / develop Issue 14 / Video Digitizing / HackTV & Example panel comp. / HackTV.c < prev    next >
Encoding:
Text File  |  1993-03-18  |  28.4 KB  |  1,161 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        HackTV.c
  3.  
  4.     Contains:    Hack TV routines.
  5.             
  6.                 Refer to develop Issue 13, "Video Digitizing Under QuickTime",
  7.                 for details on this code.
  8.                 
  9.                 This code requires QuickTime 1.5.
  10.                 
  11.                 This version of HackTV.c includes a section to link in the
  12.                 example video panel component.
  13.  
  14.     Written by:    Gary Woodcock
  15.  
  16.     Copyright:    © 1992-1993 by Apple Computer, Inc.
  17.  
  18.     Change History (most recent first):
  19.  
  20. */
  21.  
  22. //-----------------------------------------------------------------------
  23. // Includes
  24.  
  25. #include <Menus.h>
  26. #include <Windows.h>
  27. #include <QuickDraw.h>
  28. #include <OSEvents.h>
  29. #include <Resources.h>
  30. #include <Desk.h>
  31. #include <Fonts.h>
  32. #include <ToolUtils.h>
  33. #include <QuickTimeComponents.h>
  34. #include <Scrap.h>
  35. #include <Printing.h>
  36. #include <Errors.h>
  37. #include <SysEqu.h>
  38. #include <Folders.h>
  39. #include <Script.h>
  40. #include <Memory.h>
  41. #include <GestaltEqu.h>
  42.  
  43. #ifndef THINK_C
  44.     #include <Packages.h>
  45. #endif THINK_C
  46.  
  47. #include "softVdig.h"
  48. #include "ExampleVideoPanelPrivate.h"
  49.  
  50. //-----------------------------------------------------------------------
  51. // Constants
  52.  
  53. // Menu bar
  54. enum
  55. {
  56.     kMenuBarID = 128
  57. };
  58.  
  59. // Menus
  60. enum
  61. {
  62.     kAppleID = 128,
  63.     kFileID,
  64.     kEditID,
  65.     kMonitorID
  66. };
  67.  
  68. // Apple menu items
  69. enum
  70. {
  71.     kAboutItem = 1
  72. };
  73.  
  74. // File menu items
  75. enum
  76. {
  77.     kPageSetupItem = 1,
  78.     kPrintItem,
  79.     kQuitItem = 4
  80. };
  81.  
  82. // Edit menu items
  83. enum
  84. {
  85.     kUndoItem = 1,
  86.     kCutItem = 3,
  87.     kCopyItem,
  88.     kPasteItem,
  89.     kClearItem
  90. };
  91.  
  92. // Monitor menu items
  93. enum
  94. {
  95.     kVideoSettingsItem = 1,
  96.     kSoundSettingsItem,
  97.     kQuarterSizeItem = 4,
  98.     kHalfSizeItem,
  99.     kFullSizeItem,
  100.     kRecordItem = 8
  101. };
  102.  
  103. // Dialog IDs
  104. enum
  105. {
  106.     kAboutDLOGID = 128,
  107.     kMonitorDLOGID
  108. };
  109.  
  110. // Common DITL items
  111. enum
  112. {
  113.     kAboutOKButton = 1,
  114.     kAboutOKButtonOutline
  115. };
  116.  
  117. //-----------------------------------------------------------------------
  118. // Globals
  119.  
  120. MenuHandle                gAppleMenu;
  121. MenuHandle                gFileMenu;
  122. MenuHandle                gEditMenu;
  123. MenuHandle                gMonitorMenu;
  124. EventRecord                gTheEvent;
  125. Boolean                    gQuitFlag;
  126. SeqGrabComponent        gSeqGrabber;
  127. SGChannel                gVideoChannel;
  128. SGChannel                gSoundChannel;
  129. WindowPtr                gMonitor;
  130. Rect                    gActiveVideoRect;
  131. PicHandle                gMonitorPICT;
  132. Boolean                    gFullSize;
  133. Boolean                    gHalfSize;
  134. Boolean                    gQuarterSize;
  135. THPrint                    gPrintRec;
  136. AlignmentProcRecordPtr    gSeqGrabberAlignProc;
  137. VideoDigitizerComponent    gVdig;
  138.  
  139. //-----------------------------------------------------------------------
  140. // Prototypes
  141.  
  142. static void
  143. DoInit (void);
  144.  
  145. static void
  146. DoMenuSetup (void);
  147.  
  148. static void
  149. HandleEvent (void);
  150.  
  151. static void
  152. HandleMouseDown    (void);
  153.  
  154. static void
  155. AdjustMenus (void);
  156.  
  157. static void
  158. Enable (Handle menu, short item, Boolean ok);
  159.  
  160. static void
  161. HandleMenu (long menu);
  162.  
  163. static void
  164. DoAboutDialog (void);
  165.  
  166. static void
  167. DoQuit (void);
  168.  
  169. pascal void
  170. AboutDrawProc (DialogPtr theDialog, short theItemNum);
  171.  
  172. static OSErr
  173. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn);
  174.  
  175. pascal Boolean
  176. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  177.     short *itemHit, long refCon);
  178.  
  179. static Boolean
  180. HasQuickTime15 (void);
  181.  
  182. //-----------------------------------------------------------------------
  183.  
  184. main (void)
  185. {
  186.     // Init
  187.     DoInit();
  188.     DoMenuSetup();
  189.     
  190.     // Eat events until done
  191.     do
  192.     {
  193.         HandleEvent();
  194.     }
  195.     while (!gQuitFlag);
  196.     
  197.     // Take off, eh?
  198.     ExitToShell();
  199. }
  200.  
  201. //-----------------------------------------------------------------------
  202.  
  203. static void
  204. DoInit (void)
  205. {
  206.     ComponentDescription    theDesc;
  207.     ComponentResult            result = noErr;
  208.     Component                sgCompID = 0L;
  209.     GrafPtr                    savedPort;
  210.     Component                vdigCompID;            // kck
  211.     Component                xmplPanelID;
  212.     
  213.     // Set up quit flag
  214.     gQuitFlag = false;
  215.     
  216.     // MacMantra™
  217.     MaxApplZone();
  218.     InitGraf (&qd.thePort);
  219.     InitFonts();
  220.     FlushEvents (everyEvent, 0);
  221.     InitWindows();
  222.     InitMenus();
  223.     TEInit();
  224.     InitDialogs (0L);
  225.     InitCursor();
  226.     EnterMovies();
  227.     MoreMasters();
  228.     MoreMasters();
  229.     MoreMasters();
  230.     MoreMasters();
  231.     
  232.     // Init stuff
  233.     gSeqGrabber = 0L;
  234.     gVideoChannel = 0L;
  235.     gSoundChannel = 0L;
  236.     gMonitorPICT = nil;
  237.     gPrintRec = (THPrint) NewHandleClear (sizeof (TPrint));
  238.     
  239.     // Find and open a sequence grabber
  240.     theDesc.componentType = SeqGrabComponentType;
  241.     theDesc.componentSubType = 0L;
  242.     theDesc.componentManufacturer = 'appl';
  243.     theDesc.componentFlags = 0L;
  244.     theDesc.componentFlagsMask = 0L;    
  245.     sgCompID = FindNextComponent (nil, &theDesc);
  246.     if (sgCompID != 0L)
  247.     {
  248.         gSeqGrabber = OpenComponent (sgCompID);
  249.     }
  250.     
  251.     // Find the softVdig
  252.     #ifdef DEBUG_IT
  253.         vdigCompID = RegisterSoftVdig();
  254.     #else
  255.         theDesc.componentType = videoDigitizerComponentType;
  256.         theDesc.componentSubType = 'soft';
  257.         theDesc.componentManufacturer = 'jph ';
  258.         theDesc.componentFlags = 0L;
  259.         theDesc.componentFlagsMask = 0L;
  260.         vdigCompID = FindNextComponent (nil, &theDesc);
  261.         SetDefaultComponent (vdigCompID, defaultComponentAnyFlagsAnyManufacturerAnySubType);
  262.     #endif DEBUG_IT
  263.     
  264.     // Register the example video panel component
  265.     #ifdef DEBUG_ME
  266.         xmplPanelID = RegisterExampleVideoPanel();
  267.     #endif DEBUG_ME
  268.  
  269.     // If we got a sequence grabber, set it up
  270.     if (gSeqGrabber != 0L)
  271.     {
  272.         // Get the monitor
  273.         gMonitor = GetNewDialog (kMonitorDLOGID, nil, (WindowPtr) -1L);
  274.         if (gMonitor != nil)
  275.         {
  276.             // Initialize the sequence grabber
  277.             GetPort (&savedPort);
  278.             SetPort (gMonitor);
  279.             ShowWindow (gMonitor);        
  280.             result = SGInitialize (gSeqGrabber);
  281.             if (result == noErr)
  282.             {
  283.                 result = SGSetGWorld (gSeqGrabber, (CGrafPtr) gMonitor, nil);
  284.                 
  285.                 // Get a video channel
  286.                 result = SGNewChannel (gSeqGrabber, VideoMediaType, &gVideoChannel);
  287.                 if ((gVideoChannel != nil) && (result == noErr))
  288.                 {
  289.                     short    width;
  290.                     short    height;
  291.                     
  292.                     gQuarterSize = false;
  293.                     gHalfSize = true;
  294.                     gFullSize = false;
  295.                     
  296.                     result = SGGetSrcVideoBounds (gVideoChannel, &gActiveVideoRect);
  297.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  298.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  299.                     SizeWindow (gMonitor, width, height, false);
  300.                     
  301.                     result = SGSetChannelUsage (gVideoChannel, seqGrabPreview | seqGrabRecord | seqGrabPlayDuringRecord);
  302.                     result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  303.                 }
  304.                 
  305.                 // Get a sound channel
  306.                 result = SGNewChannel (gSeqGrabber, SoundMediaType, &gSoundChannel);
  307.                 if ((gSoundChannel != nil) && (result == noErr))
  308.                 {
  309.                     if (HasQuickTime15())
  310.                     {
  311.                         // There is a bug in QuickTime 1.5 where a SGChannel of type sound
  312.                         // will return successfully if there is no sound driver present.
  313.                         // To get around this, if we're running QT 1.5, we call 
  314.                         // SGGetSoundInputDriver after a successful SGNewChannel call for
  315.                         // a sound channel to find out if we really got one.  QuickTime
  316.                         // 1.6 has fixed this problem.
  317.                         
  318.                         short    sndDrvrRefNum = SGGetSoundInputDriver (gSoundChannel);
  319.                         
  320.                         if (sndDrvrRefNum == 0)
  321.                         {
  322.                             result = SGDisposeChannel (gSeqGrabber, gSoundChannel);
  323.                             gSoundChannel = nil;
  324.                         }
  325.                     }
  326.                     
  327.                     if (gSoundChannel != nil)
  328.                     {
  329.                         result = SGSetChannelUsage (gSoundChannel, seqGrabPreview | seqGrabRecord);
  330.                         
  331.                         // Set the volume low to prevent feedback when we start the preview,
  332.                         // in case the mic is anywhere near the speaker.
  333.                         result = SGSetChannelVolume (gSoundChannel, 0x0010);
  334.                     }
  335.                 }
  336.                 
  337.                 // Get the alignment proc (for use when dragging the monitor)
  338.                 result = SGGetAlignmentProc (gSeqGrabber, gSeqGrabberAlignProc);
  339.                 
  340.                 // Get ready…
  341.                 //result = SGPrepare (gSeqGrabber, true, true);
  342.             }
  343.             
  344.             // Go!
  345.             if(result == noErr) result = SGStartPreview (gSeqGrabber);
  346.             SetPort (savedPort);
  347.         }
  348.     }
  349. }
  350.  
  351. //-----------------------------------------------------------------------
  352.  
  353. static void
  354. DoMenuSetup (void)
  355. {    
  356.     Handle    theMenuBar = GetNewMBar (kMenuBarID);
  357.     
  358.     // Set up our menus
  359.     SetMenuBar (theMenuBar);
  360.     gAppleMenu = GetMHandle (kAppleID);
  361.     gFileMenu = GetMHandle (kFileID);
  362.     gEditMenu = GetMHandle (kEditID);
  363.     gMonitorMenu = GetMHandle (kMonitorID);
  364.     AddResMenu (gAppleMenu, 'DRVR');
  365.     
  366.     // Last minute adjustments…
  367.     AdjustMenus();
  368. }
  369.  
  370. //-----------------------------------------------------------------------
  371.  
  372. static void
  373. HandleEvent (void)
  374. {
  375.     ComponentResult    result = noErr;
  376.  
  377.     // Do system stuff
  378.     HiliteMenu (0);
  379.     SystemTask();
  380.     
  381.     // Give some time to the sequence grabber
  382.     if (gSeqGrabber != 0L)
  383.         result = SGIdle (gSeqGrabber);
  384.     
  385.     // Suck an event
  386.     if (WaitNextEvent (everyEvent, &gTheEvent, 0, 0))
  387.     {
  388.         // What was it?
  389.         switch (gTheEvent.what)
  390.         {
  391.             case mouseDown:
  392.             {
  393.                 // Handle it
  394.                 HandleMouseDown();
  395.                 break;
  396.             }
  397.             case keyDown:
  398.             case autoKey:
  399.             {
  400.                 char    theChar = gTheEvent.message & charCodeMask;
  401.                 long    theMenu = MenuKey (theChar);
  402.  
  403.                 // Handle menu command keys
  404.                 HandleMenu (theMenu);                
  405.                 break;
  406.             }
  407.             case updateEvt:
  408.             {
  409.                 if ((gMonitor != nil) && ((WindowPtr) (gTheEvent.message) == (WindowPtr) gMonitor))
  410.                 {
  411.                     // Eat the update
  412.                     BeginUpdate (gMonitor);
  413.                     EndUpdate (gMonitor);
  414.                 }
  415.                 break;
  416.             }
  417.             default:    // We don't really care about any other events, but you might, so feel free
  418.             {
  419.                 break;
  420.             }
  421.         }
  422.     }
  423. }
  424.  
  425. //-----------------------------------------------------------------------
  426.  
  427. static void
  428. HandleMouseDown (void)
  429. {    
  430.     WindowPtr    theWindow;
  431.     short        windowCode = FindWindow (gTheEvent.where, &theWindow);
  432.     
  433.     // Where was the mouse down?
  434.     switch (windowCode)
  435.     {
  436.         case inSysWindow:
  437.         { 
  438.             SystemClick (&gTheEvent, theWindow);
  439.             break;
  440.         }
  441.         case inMenuBar:
  442.         {
  443.             AdjustMenus();
  444.             HandleMenu (0L);
  445.             break;
  446.         }
  447.         case inDrag:
  448.         {
  449.             // Was it the monitor?
  450.             if (theWindow == gMonitor)
  451.             {
  452.                 ComponentResult    result = noErr;
  453.                 Rect            limitRect;
  454.                 RgnHandle        grayRgn = GetGrayRgn();
  455.                 Rect            boundsRect;
  456.                 
  457.                 // Find bounds
  458.                 if (grayRgn != nil)
  459.                 {
  460.                     limitRect = (*grayRgn)->rgnBBox;
  461.                 }
  462.                 else
  463.                 {
  464.                     limitRect = qd.screenBits.bounds;
  465.                 }
  466.                 
  467.                 // Pause the sequence grabber
  468.                 result = SGPause (gSeqGrabber, true);
  469.                 
  470.                 if (gVideoChannel != nil)
  471.                 {
  472.                     // Drag it with the totally cool DragAlignedWindow
  473.                       // Note that the sequence grabber can get real confused when you use this
  474.                       // call if you've got multiple video channels - this'll get fixed in the 
  475.                       // next release.  
  476.                       result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  477.                     DragAlignedWindow (theWindow, gTheEvent.where, &limitRect, &boundsRect, gSeqGrabberAlignProc);
  478.                 }
  479.                 else
  480.                 {
  481.                     DragWindow (theWindow, gTheEvent.where, &limitRect);
  482.                 }
  483.                 
  484.                 // Start up the sequence grabber
  485.                 result = SGPause (gSeqGrabber, false);
  486.             }
  487.             break;
  488.         }
  489.         default:
  490.         {
  491.             break;
  492.         }
  493.     }
  494. }
  495.  
  496. //-----------------------------------------------------------------------
  497.  
  498. static void
  499. AdjustMenus (void)
  500. {
  501.     register WindowPeek        wp = nil;
  502.     short                    kind = 0;
  503.     Boolean                    DA = false;
  504.     ComponentResult            result = noErr;
  505.     
  506.     // What kind of window is frontmost?
  507.     wp = (WindowPeek) FrontWindow();
  508.     kind = wp ? wp->windowKind : 0;
  509.     DA = kind < 0;
  510.     
  511.     // Set our menu item states appropriately
  512.     
  513.     // Apple menu
  514.     Enable ((Handle) gAppleMenu, kAboutItem, true);    
  515.     
  516.     // File menu
  517.     Enable ((Handle) gFileMenu, kPageSetupItem, true);
  518.     Enable ((Handle) gFileMenu, kPrintItem, (gVideoChannel != 0L ? true : false));
  519.     Enable ((Handle) gFileMenu, kQuitItem, true);
  520.  
  521.     // Edit menu
  522.     Enable ((Handle) gEditMenu, kUndoItem, DA);
  523.     Enable ((Handle) gEditMenu, kCutItem, DA || (gVideoChannel != 0L));
  524.     Enable ((Handle) gEditMenu, kCopyItem, DA || (gVideoChannel != 0L));
  525.     Enable ((Handle) gEditMenu, kPasteItem, DA);
  526.     Enable ((Handle) gEditMenu, kClearItem, DA);
  527.     
  528.     // Monitor menu
  529.     Enable ((Handle) gMonitorMenu, kVideoSettingsItem, (gVideoChannel != 0L ? true : false));
  530.     Enable ((Handle) gMonitorMenu, kSoundSettingsItem, (gSoundChannel != 0L ? true : false));
  531.     Enable ((Handle) gMonitorMenu, kQuarterSizeItem, (gVideoChannel != 0L ? true : false));
  532.     CheckItem (gMonitorMenu, kQuarterSizeItem, gQuarterSize);
  533.     Enable ((Handle) gMonitorMenu, kHalfSizeItem, (gVideoChannel != 0L ? true : false));
  534.     CheckItem (gMonitorMenu, kHalfSizeItem, gHalfSize);
  535.     Enable ((Handle) gMonitorMenu, kFullSizeItem, (gVideoChannel != 0L ? true : false));
  536.     CheckItem (gMonitorMenu, kFullSizeItem, gFullSize);
  537.     Enable ((Handle) gMonitorMenu, kRecordItem, (gVideoChannel != 0L ? true : false));
  538.     
  539.     // Draw it
  540.     DrawMenuBar();
  541. }
  542.  
  543. //-----------------------------------------------------------------------
  544.  
  545. static void
  546. Enable (Handle menu, short item, Boolean ok)
  547. {
  548.     // Utility routine to enable and disable menu items
  549.     if (ok)
  550.     {
  551.         EnableItem ((MenuHandle) menu, item);
  552.     }
  553.     else
  554.     {
  555.         DisableItem ((MenuHandle) menu, item);
  556.     }
  557. }
  558.  
  559. //-----------------------------------------------------------------------
  560.  
  561. static void
  562. HandleMenu (long theMenu)
  563. {    
  564.     long            mSelect;
  565.     short            menuID;
  566.     short            menuItem;
  567.     ComponentResult    result = noErr;    
  568.     Str255            menuItemStr;
  569.     
  570.     // Did we get a menu?
  571.     if (theMenu == 0L)
  572.     {
  573.         // Nope, get it from menu select
  574.         mSelect = MenuSelect (gTheEvent.where);
  575.     }
  576.     else
  577.     {
  578.         // Yep, use it
  579.         mSelect = theMenu;
  580.     }
  581.     
  582.     // Decode it
  583.     menuID = HiWord (mSelect);
  584.     menuItem = LoWord (mSelect);
  585.     
  586.     // Which menu is it?
  587.     switch (menuID)
  588.     {
  589.         case kAppleID:
  590.         {
  591.             if (menuItem == kAboutItem)
  592.             {
  593.                 // Do the boring about box
  594.                 DoAboutDialog();
  595.             }
  596.             else    // It's a DA
  597.             {
  598.                 Str255    name;
  599.                 GrafPtr    savedPort;
  600.                 
  601.                 // Open the DA
  602.                 GetPort (&savedPort);
  603.                 GetItem (gAppleMenu, menuItem, name);
  604.                 OpenDeskAcc (name);
  605.                 SetPort (savedPort);
  606.             }
  607.             break;
  608.         }
  609.         case kFileID:
  610.         {
  611.             switch (menuItem)
  612.             {
  613.                 case kPageSetupItem:
  614.                 {
  615.                     // Do the page setup dialog
  616.                     PrOpen();
  617.                     PrStlDialog (gPrintRec);
  618.                     PrClose();
  619.                     break;
  620.                 }
  621.                 case kPrintItem:
  622.                 {
  623.                     TPPrPort    printPort;
  624.                     TPrStatus    printStatus;
  625.                     
  626.                     // Copy a frame from the monitor
  627.                     if (gMonitorPICT != nil)
  628.                     {
  629.                         KillPicture (gMonitorPICT);
  630.                     }
  631.                     gMonitorPICT = nil;
  632.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  633.                     if ((result == noErr) && (gMonitorPICT != nil))
  634.                     {
  635.                         // Print it
  636.                         HLock ((Handle) gMonitorPICT);
  637.                         PrOpen();
  638.                         if (PrJobDialog (gPrintRec))
  639.                         {
  640.                             printPort = PrOpenDoc (gPrintRec, nil, nil);
  641.                             result = PrError();
  642.                             PrOpenPage (printPort, 0);
  643.                             result = PrError();
  644.                             DrawPicture (gMonitorPICT, &((**gMonitorPICT).picFrame));
  645.                             PrClosePage (printPort);
  646.                             result = PrError();
  647.                             PrCloseDoc (printPort);
  648.                             result = PrError();
  649.                             if ((**gPrintRec).prJob.bJDocLoop == bSpoolLoop)
  650.                             {
  651.                                 PrPicFile (gPrintRec, 0, 0, 0, &printStatus);
  652.                                 result = PrError();
  653.                             }
  654.                         }
  655.                         PrClose();
  656.                         result = PrError();
  657.                         HUnlock ((Handle) gMonitorPICT);
  658.                     }
  659.                     break;
  660.                 }
  661.                 case kQuitItem:
  662.                 {
  663.                     // Let's scram
  664.                     DoQuit();
  665.                     break;
  666.                 }
  667.             }
  668.             break;
  669.         }
  670.         case kEditID:
  671.         {
  672.             // Is this a DA kind of thing?
  673.             if (!SystemEdit (menuItem - 1))
  674.             {
  675.                 // We only do cut and copy
  676.                 if ((menuItem == kCutItem) || (menuItem == kCopyItem))
  677.                 {
  678.                     // Copy a frame from the monitor
  679.                     if (gMonitorPICT != nil)
  680.                     {
  681.                         KillPicture (gMonitorPICT);
  682.                     }
  683.                     gMonitorPICT = nil;
  684.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  685.                     if ((result == noErr) && (gMonitorPICT != nil))
  686.                     {
  687.                         result = ZeroScrap();
  688.                         HLock ((Handle) gMonitorPICT);
  689.                         result = PutScrap (GetHandleSize ((Handle) gMonitorPICT), 'PICT', *(Handle)gMonitorPICT);
  690.                         HUnlock ((Handle) gMonitorPICT);
  691.                         if (result != noErr)
  692.                         {
  693.                             // Cut or copy failed, probably due to lack of memory
  694.                         }
  695.                     }
  696.                 }
  697.             }
  698.             break;
  699.         }
  700.         case kMonitorID:
  701.         {
  702.             switch (menuItem)
  703.             {
  704.                 short        width;
  705.                 short        height;
  706.                 Rect        curBounds;
  707.                 Rect        curVideoRect;
  708.                 Rect        newVideoRect;
  709.                 Rect        newBounds;
  710.                 Rect        maxBoundsRect;
  711.                 GrafPtr        savedPort;
  712.                 RgnHandle    deadRgn;
  713.                 Rect        boundsRect;
  714.                     
  715.                 case kVideoSettingsItem:
  716.                 {
  717.                     if ((gSeqGrabber != 0L) && (gVideoChannel != 0L))
  718.                     {
  719.                         Rect    newActiveVideoRect;
  720.                         Rect    adjustedActiveVideoRect;
  721.                         
  722.                         // Get our current state
  723.                         result = SGGetChannelBounds (gVideoChannel, &curBounds);
  724.                         result = SGGetVideoRect (gVideoChannel, &curVideoRect);
  725.                         
  726.                         // Pause
  727.                         result = SGPause (gSeqGrabber, true);
  728.                         
  729.                         // Do the dialog thang
  730.                         result = SGSettingsDialog (gSeqGrabber, gVideoChannel, 0, 
  731.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  732.                             
  733.                         // What happened?
  734.                         result = SGGetVideoRect (gVideoChannel, &newVideoRect);
  735.                         result = SGGetSrcVideoBounds (gVideoChannel, &newActiveVideoRect);
  736.  
  737.                         // Set up our port
  738.                         GetPort (&savedPort);
  739.                         SetPort (gMonitor);
  740.                         
  741.                         // Has our active rect changed?
  742.                         // If so, it's because our video standard changed (e.g., NTSC to PAL),
  743.                         // and we need to adjust our monitor window
  744.                         if (!EqualRect (&gActiveVideoRect, &newActiveVideoRect))
  745.                         {
  746.                             if (gFullSize)
  747.                             {
  748.                                 width = newActiveVideoRect.right - newActiveVideoRect.left;
  749.                                 height = newActiveVideoRect.bottom - newActiveVideoRect.top;
  750.                                 
  751.                                 gActiveVideoRect = newActiveVideoRect;
  752.                                 SizeWindow (gMonitor, width, height, false);
  753.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  754.                             }
  755.                             else if (gHalfSize)
  756.                             {
  757.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 2;
  758.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 2;
  759.                                 
  760.                                 gActiveVideoRect = newActiveVideoRect;
  761.                                 SizeWindow (gMonitor, width, height, false);
  762.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  763.                             }
  764.                             else if (gQuarterSize)
  765.                             {
  766.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 4;
  767.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 4;
  768.                                 
  769.                                 gActiveVideoRect = newActiveVideoRect;
  770.                                 SizeWindow (gMonitor, width, height, false);
  771.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  772.                             }
  773.                         }
  774.                         
  775.                         // Has our crop changed?
  776.                         // This code shows how to be crop video panel friendly
  777.                         // Two important things - 
  778.                         // 1) Be aware that you might have been cropped and adjust your
  779.                         //    video window appropriately
  780.                         // 2) Be aware that you might have been adjusted and attempt to
  781.                         //    account for this.  Adjusting refers to using the digitizer
  782.                         //    rect to "adjust" the active source rect within the maximum
  783.                         //    source rect.  This is useful if you're getting those nasty
  784.                         //    black bands on the sides of your video display - you can use
  785.                         //    the control-arrow key sequence to shift the active source 
  786.                         //    rect around when you're in the crop video panel
  787.                         
  788.                         adjustedActiveVideoRect = gActiveVideoRect;
  789.                         if (!EqualRect (&curVideoRect, &newVideoRect))
  790.                         {
  791.                             if ((newVideoRect.left < gActiveVideoRect.left) ||
  792.                                 (newVideoRect.right > gActiveVideoRect.right) ||
  793.                                 (newVideoRect.top < gActiveVideoRect.top) ||
  794.                                 (newVideoRect.bottom > gActiveVideoRect.bottom))
  795.                             {
  796.                                 if (newVideoRect.left < gActiveVideoRect.left)
  797.                                 {
  798.                                     adjustedActiveVideoRect.left = newVideoRect.left;
  799.                                     adjustedActiveVideoRect.right -= (gActiveVideoRect.left - newVideoRect.left);
  800.                                 }
  801.                                 if (newVideoRect.right > gActiveVideoRect.right)
  802.                                 {
  803.                                     adjustedActiveVideoRect.right = newVideoRect.right;
  804.                                     adjustedActiveVideoRect.left += (newVideoRect.right - gActiveVideoRect.right);
  805.                                 }
  806.                                 if (newVideoRect.top < gActiveVideoRect.top)
  807.                                 {
  808.                                     adjustedActiveVideoRect.top = newVideoRect.top;
  809.                                     adjustedActiveVideoRect.bottom -= (gActiveVideoRect.top - newVideoRect.top);
  810.                                 }
  811.                                 if (newVideoRect.bottom > gActiveVideoRect.bottom)
  812.                                 {
  813.                                     adjustedActiveVideoRect.bottom = newVideoRect.bottom;
  814.                                     adjustedActiveVideoRect.top += (newVideoRect.bottom - gActiveVideoRect.bottom);
  815.                                 }
  816.                                 newBounds = newVideoRect;
  817.                                 MapRect (&newBounds, &adjustedActiveVideoRect, &(gMonitor->portRect));
  818.                             }
  819.                             else    // Can't tell if we've been adjusted (digitizer rect is smaller on all sides
  820.                                     // than the active source rect)
  821.                             {
  822.                                 newBounds = newVideoRect;
  823.                                 MapRect (&newBounds, &gActiveVideoRect, &(gMonitor->portRect));
  824.                             }
  825.                             width = newBounds.right - newBounds.left;
  826.                             height = newBounds.bottom - newBounds.top;
  827.                             result = SGSetChannelBounds (gVideoChannel, &newBounds);
  828.                         }
  829.  
  830.                         // Clean out the part of the port that isn't being drawn in
  831.                         deadRgn = NewRgn();
  832.                         if (deadRgn != nil)
  833.                         {
  834.                             result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  835.                             result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  836.                             EraseRgn (deadRgn);
  837.                             DisposeRgn (deadRgn);
  838.                         }
  839.  
  840.                         SetPort (savedPort);
  841.                         
  842.                         // The pause that refreshes
  843.                         result = SGPause (gSeqGrabber, false);
  844.                     }
  845.                     break;
  846.                 }
  847.                 case kSoundSettingsItem:
  848.                 {
  849.                     if ((gSeqGrabber != 0L) && (gSoundChannel != 0L))
  850.                     {
  851.                         // Do the dialog thang
  852.                         result = SGSettingsDialog (gSeqGrabber, gSoundChannel, 0,
  853.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  854.                     }
  855.                     break;
  856.                 }
  857.                 case kQuarterSizeItem:
  858.                 {
  859.                     // New width and height
  860.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 4;
  861.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 4;
  862.                     
  863.                     // Set flags and menus
  864.                     gQuarterSize = true;
  865.                     gHalfSize = false;
  866.                     gFullSize = false;
  867.                     AdjustMenus();
  868.                     
  869.                     // Resize the monitor
  870.                     GetPort (&savedPort);
  871.                     SetPort (gMonitor);
  872.                     result = SGPause (gSeqGrabber, true);
  873.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  874.                     maxBoundsRect = gMonitor->portRect;
  875.                     SizeWindow (gMonitor, width, height, false);
  876.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  877.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  878.  
  879.                     // Clean out part of port we're not drawing in
  880.                     deadRgn = NewRgn();
  881.                     if (deadRgn != nil)
  882.                     {
  883.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  884.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  885.                         EraseRgn (deadRgn);
  886.                         DisposeRgn (deadRgn);
  887.                     }
  888.                         
  889.                     SetPort (savedPort);
  890.                     result = SGPause (gSeqGrabber, false);
  891.                     break;
  892.                 }
  893.                 case kHalfSizeItem:
  894.                 {
  895.                     // New width and height
  896.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  897.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  898.                     
  899.                     // Set flags and menus
  900.                     gQuarterSize = false;
  901.                     gHalfSize = true;
  902.                     gFullSize = false;
  903.                     AdjustMenus();
  904.                     
  905.                     // Resize the monitor
  906.                     GetPort (&savedPort);
  907.                     SetPort (gMonitor);
  908.                     result = SGPause (gSeqGrabber, true);
  909.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  910.                     maxBoundsRect = gMonitor->portRect;
  911.                     SizeWindow (gMonitor, width, height, false);
  912.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  913.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  914.  
  915.                     // Clean out part of port we're not drawing in
  916.                     deadRgn = NewRgn();
  917.                     if (deadRgn != nil)
  918.                     {
  919.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  920.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  921.                         EraseRgn (deadRgn);
  922.                         DisposeRgn (deadRgn);
  923.                     }
  924.                         
  925.                     SetPort (savedPort);
  926.                     result = SGPause (gSeqGrabber, false);
  927.                     break;
  928.                 }
  929.                 case kFullSizeItem:
  930.                 {
  931.                     // New width and height
  932.                     width = gActiveVideoRect.right - gActiveVideoRect.left;
  933.                     height = gActiveVideoRect.bottom - gActiveVideoRect.top;
  934.                     
  935.                     // Set flags and menus
  936.                     gQuarterSize = false;
  937.                     gHalfSize = false;
  938.                     gFullSize = true;
  939.                     AdjustMenus();
  940.                     
  941.                     // Resize the monitor
  942.                     GetPort (&savedPort);
  943.                     SetPort (gMonitor);
  944.                     result = SGPause (gSeqGrabber, true);
  945.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  946.                     maxBoundsRect = gMonitor->portRect;
  947.                     SizeWindow (gMonitor, width, height, false);
  948.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  949.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  950.  
  951.                     // Clean out part of port we're not drawing in
  952.                     deadRgn = NewRgn();
  953.                     if (deadRgn != nil)
  954.                     {
  955.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  956.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  957.                         EraseRgn (deadRgn);
  958.                         DisposeRgn (deadRgn);
  959.                     }
  960.                         
  961.                     SetPort (savedPort);
  962.                     result = SGPause (gSeqGrabber, false);
  963.                     break;
  964.                 }
  965.                 case kRecordItem:
  966.                 {
  967.                     FSSpec    theFSSpec;
  968.                     long    savedDirID = *(long *) CurDirStore;
  969.                     long    dirID;
  970.                     short    savedVRefNum = *(short *) SFSaveDisk;
  971.                     short    vRefNum;
  972.                     
  973.                     result = FindFolder (kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  974.                         &vRefNum, &dirID);
  975.                     *(short *)SFSaveDisk = -vRefNum;
  976.                     *(long *)CurDirStore = dirID;
  977.                     
  978.                     result = FSMakeFSSpec (vRefNum, dirID, "\pHack MooV", &theFSSpec);
  979.                     result = DeleteMovieFile (&theFSSpec);
  980.                     result = CreateMovieFile (&theFSSpec, 'TVOD', smSystemScript,
  981.                         createMovieFileDontOpenFile | createMovieFileDontCreateMovie,
  982.                         nil, nil);
  983.                     result = SGStop (gSeqGrabber);
  984.                     result = SGSetDataOutput (gSeqGrabber, &theFSSpec, seqGrabToDisk);
  985.                     result = SGStartRecord (gSeqGrabber);
  986.                     while (!Button() && (result == noErr))
  987.                     {
  988.                         result = SGIdle (gSeqGrabber);
  989.                     }
  990.                     result = SGStop (gSeqGrabber);
  991.                     result = SGStartPreview (gSeqGrabber);
  992.                     
  993.                     *(short *)SFSaveDisk = savedVRefNum;
  994.                     *(long *)CurDirStore = savedDirID;
  995.                     break;
  996.                 }
  997.                 default:
  998.                 {
  999.                     break;
  1000.                 }
  1001.             }
  1002.         }
  1003.         default:
  1004.         {
  1005.             break;
  1006.         }
  1007.     }
  1008. }
  1009.  
  1010. //-----------------------------------------------------------------------
  1011.  
  1012. static void
  1013. DoAboutDialog (void)
  1014. {
  1015.     short        itemHit;
  1016.     short        itemType;
  1017.     Handle        itemHandle;
  1018.     Rect        itemRect;
  1019.     DialogPtr    aboutDialog = GetNewDialog (kAboutDLOGID, nil, (WindowPtr)-1L);
  1020.  
  1021.     // Do the boring about dialog
  1022.     GetDItem (aboutDialog, kAboutOKButtonOutline, &itemType, &itemHandle, &itemRect);
  1023.     SetDItem (aboutDialog, kAboutOKButtonOutline, itemType, 
  1024.         (Handle) AboutDrawProc, &itemRect);
  1025.  
  1026.     ShowWindow (aboutDialog);
  1027.     do
  1028.     {
  1029.         ModalDialog (nil, &itemHit);
  1030.     }
  1031.     while (itemHit != kAboutOKButton);
  1032.     DisposDialog (aboutDialog);
  1033. }
  1034.  
  1035. //-----------------------------------------------------------------------
  1036.  
  1037. pascal void
  1038. AboutDrawProc (DialogPtr theDialog, short theItemNum)
  1039. {
  1040.     PenState    thePenState;
  1041.     OSErr        result = noErr;
  1042.     Rect        itemRect;
  1043.     Handle        itemHandle;
  1044.     short        itemType;
  1045.     
  1046.     // Set up the pen
  1047.     GetPenState (&thePenState);
  1048.     
  1049.     GetDItem (theDialog, theItemNum, &itemType, &itemHandle, &itemRect);
  1050.     
  1051.     // What item do we need to draw?
  1052.     switch (theItemNum)
  1053.     {
  1054.         case kAboutOKButtonOutline:
  1055.             PenNormal();
  1056.             PenMode (patCopy);
  1057.             PenSize (3, 3);
  1058.             InsetRect (&itemRect, -4, -4);
  1059.             FrameRoundRect (&itemRect, 16, 16);
  1060.             break;
  1061.         default:
  1062.             break;
  1063.     }
  1064.     
  1065.     // Restore the pen
  1066.     SetPenState (&thePenState);
  1067. }
  1068.  
  1069. //-----------------------------------------------------------------------
  1070.  
  1071. static OSErr
  1072. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn)
  1073. {
  1074.     RgnHandle    srcRgnA = NewRgn();
  1075.     RgnHandle    srcRgnB = NewRgn();
  1076.     OSErr        result = noErr;
  1077.     
  1078.     if ((destRgn != nil) && (*destRgn != nil))
  1079.     {
  1080.         if ((srcRgnA != nil) &&
  1081.             (srcRgnB != nil))
  1082.         {
  1083.             RectRgn (srcRgnA, srcRectA);
  1084.             RectRgn (srcRgnB, srcRectB);
  1085.             XorRgn (srcRgnA, srcRgnB, *destRgn);
  1086.             DisposeRgn (srcRgnA);
  1087.             DisposeRgn (srcRgnB);
  1088.         }
  1089.         else
  1090.         {
  1091.             result = memFullErr;
  1092.         }
  1093.     }
  1094.     else
  1095.     {
  1096.         result = nilHandleErr;
  1097.     }
  1098.     return (result);
  1099. }
  1100.  
  1101. //-----------------------------------------------------------------------
  1102.  
  1103. pascal Boolean
  1104. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  1105.     short *itemHit, long refCon)
  1106. {
  1107.     // Ordinarily, if we had multiple windows we cared about, we'd handle
  1108.     // updating them in here, but since we don't, we'll just clear out
  1109.     // any update events meant for us
  1110.     
  1111.     Boolean    handled = false;
  1112.     
  1113.     if ((theEvent->what == updateEvt) && 
  1114.         ((WindowPtr) theEvent->message == (WindowPtr) refCon))
  1115.     {
  1116.         BeginUpdate ((WindowPtr) refCon);
  1117.         EndUpdate ((WindowPtr) refCon);
  1118.         handled = true;
  1119.     }
  1120.     return (handled);
  1121. }
  1122.  
  1123. //-----------------------------------------------------------------------
  1124.  
  1125. static Boolean
  1126. HasQuickTime15 (void)
  1127. {
  1128.     long    result;
  1129.     OSErr    err = Gestalt (gestaltQuickTime, &result);
  1130.     
  1131.     return (((err == noErr) & (result >= 0x0150)) ? true: false);
  1132. }
  1133.  
  1134. //-----------------------------------------------------------------------
  1135.  
  1136. static void
  1137. DoQuit (void)
  1138. {
  1139.     ComponentResult    result = noErr;
  1140.     
  1141.     // Clean up
  1142.     if (gSeqGrabber != 0L)
  1143.     {
  1144.         result = CloseComponent (gSeqGrabber);
  1145.         gSeqGrabber = 0L;
  1146.     }    
  1147.     
  1148.     if (gMonitor != nil)
  1149.     {
  1150.         DisposeWindow (gMonitor);
  1151.     }
  1152.     
  1153.     // Set quit flag
  1154.     gQuitFlag = true;
  1155.     
  1156.     ExitMovies();
  1157. }
  1158.  
  1159. //-----------------------------------------------------------------------
  1160.  
  1161.